package cn.anl.config;

import cn.anl.service.UserDetailServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import java.security.KeyPair;

/**
  * @Desc Oauth2鉴权服务配置类
  * @Author 安奈
  * @Date 2024/6/25 11:01
  **/
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    /**
    * @Author 安奈
    * @Desc 秘密加密
    */
    private final PasswordEncoder passwordEncoder;
    /**
    * @Author 安奈
    * @Desc 用户信息加载
    */
    private final UserDetailServiceImpl userDetailsService;
    /**
    * @Author 安奈
    * @Desc 鉴权管理
    */
    private final AuthenticationManager authenticationManager;
    /**
    * @Author 安奈
    * @Desc JWT配置
    */
    private final JwtAuthConfig jwtAuthConfig;
    /**
    * @Author 安奈
    * @Desc redis连接工厂
    */
    private final RedisConnectionFactory redisConnectionFactory;

    /**
    * @Author 安奈
    * @Desc 授权服务器配置
     * clients.inMemory()//存到内存里
     * withClient("client")//定义了一个名为"client"的OAuth2客户端
     * secret(passwordEncoder.encode("1"))//设置客户端的密码
     * scopes("all")//定义授权范围
     * authorizedGrantTypes("password","refresh_token")//定义授权类型
     * accessTokenValiditySeconds(3600)设置访问令牌有效期
     * refreshTokenValiditySeconds(86400);设置刷新令牌的有效期：
    */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()//存到内存里
                .withClient("client")//定义了一个名为"client"的OAuth2客户端
                .secret(passwordEncoder.encode("123456"))//设置客户端的密码
                .scopes("all")//定义授权范围
                .authorizedGrantTypes("authorization_code","password","refresh_token")//定义授权类型
                .redirectUris("http://www.baidu.com")//授权码模式授权后跳转路径
                .accessTokenValiditySeconds(3600)
                .refreshTokenValiditySeconds(86400);
    }

    /**
    * @Author 安奈
    * @Desc 配置授权（authorization）以及令牌（token）的访问端点和令牌服务(token services)
    */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService) //配置加载用户信息的服务
                .accessTokenConverter(accessTokenConverter())//token转码解码
                .tokenStore(redisTokenStore());//redis存储Token
    }


    /**
    * @Author 安奈
    * @Desc 授权服务安全配置
    */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.allowFormAuthenticationForClients();
    }

    /**
    * @Author 安奈
    * @Desc redis存储token
    */
    @Bean
    public TokenStore redisTokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
    /**
    * @Author 安奈
    * @Desc RAS加密生成Token
    */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setKeyPair(keyPair());
        return jwtAccessTokenConverter;
    }

    /**
    * @Author 安奈
    * @Desc 使用非对称加密算法对token签名
    */
    @Bean
    public KeyPair keyPair() {
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(jwtAuthConfig.getCertificateStoreFile()), jwtAuthConfig.getPassword().toCharArray());
        return keyStoreKeyFactory.getKeyPair(jwtAuthConfig.getAlias(), jwtAuthConfig.getPassword().toCharArray());
    }
}